#include "ThreadCache.h"

void *ThreadCache::alloc(size_t size)
{
  assert(size <= MAX_BYTES);

  size_t alignSize = SizeClass::roundUp(size);
  size_t index = SizeClass::index(size);

  if (!_freeLists[index].empty())
  {
    return _freeLists[index].pop();
  }
  else
  {
    return fetchCacheFromCentral(index, alignSize);
  }
}

void ThreadCache::dealloc(void *obj, size_t size)
{
  assert(obj);
  assert(size >= 8);
  // size_t index = SizeClass::index(obj);
  size_t index = SizeClass::index(size);
  _freeLists[index].push(obj);

  // 如果当前归还的小内存块达到了当前要的数量，那么就将内存块归还
  if(_freeLists[index].size() >= _freeLists[index].maxFetchSize()){
    listTooLong(_freeLists[index], size);
  }
}

void *ThreadCache::fetchCacheFromCentral(size_t index, size_t size)
{
  // 慢开始反馈调节算法
  // 1、最开始不会一次向central cache一次批量要太多，因为要太多了可能用不完
  // 2、如果你不要这个size大小内存需求，那么batchNum就会不断增长，直到上限
  // 3、size越大，一次向central cache要的batchNum就越小
  // 4、size越小，一次向central cache要的batchNum就越大
  int batchNum = min(SizeClass::maxFetchSize(size), _freeLists[index].maxFetchSize());

  if (batchNum == _freeLists[index].maxFetchSize())
  {
    _freeLists[index].maxFetchSize()++;
  }

  void *start, *end;
  size_t actualNum = CentralCache::getCentralCache().alloc(start, end, size, batchNum);
  if (actualNum == 1)
  {
    assert(start == end);
  }
  else
  {
    _freeLists[index].pushRange(nextObj(start), end, actualNum - 1);
  }

  return start;
}

void ThreadCache::listTooLong(FreeList &freeList, size_t size)
{
  void *start{}, *end{};
  // 一次还当前慢反馈的最大大小
  freeList.popRange(start, end, freeList.maxFetchSize());

  CentralCache::getCentralCache().dealloc(start, end, size);
}